package com.simple.relaxed.anno.impl;

import com.simple.relaxed.agent.AgentHandler;
import com.simple.relaxed.anno.AgentClass;
import com.simple.relaxed.anno.AgentMethod;
import com.simple.relaxed.exception.CannotFindInheritedInterfaceException;
import com.simple.relaxed.exception.UnableToDetermineTheInterfaceException;
import com.simple.relaxed.manager.impl.AgentManager;
import com.simple.relaxed.manager.impl.InjectManager;
import ohos.app.Context;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class AgentImpl {

    /**
     * 调用此方法，发现并且初始化代理类，并且替换InjectManager中，匹配的对象对象
     *
     * @param context
     * @throws ClassNotFoundException
     */
    public static void agentImpl(Context context) throws ClassNotFoundException {
        Map<String, Object> lookup = InjectManager.getInstance().lookup();
        for (Map.Entry<String, Object> entry : lookup.entrySet()) {
            Object value = entry.getValue();
            Class<?> aClass = value.getClass();
            AgentClass agentClass = aClass.getDeclaredAnnotation(AgentClass.class);
            if (agentClass == null) {
                continue;
            }
            String interfaceName = agentClass.interfaceName();
            Class<?> interfaceClass = null;
            if (!interfaceName.isEmpty()) {
                interfaceClass = Class.forName(interfaceName);
            } else {
                Class<?>[] interfaces = aClass.getInterfaces();
                if (interfaces.length == 0) {
                    throw new CannotFindInheritedInterfaceException("找不到继承的接口");
                } else if (interfaces.length > 1) {
                    throw new UnableToDetermineTheInterfaceException("无法确定代理的接口");
                }
                interfaceClass = interfaces[0];
            }
            Method[] methods = aClass.getDeclaredMethods();
            List<Method> ms = new ArrayList<>();
            for (Method method : methods) {
                AgentMethod agentMethod = method.getDeclaredAnnotation(AgentMethod.class);
                if (agentMethod == null) {
                    continue;
                }
                ms.add(method);
            }
            AgentHandler agentHandler = new AgentHandler(value);
            agentHandler.setContext(context);
            Object o = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{interfaceClass}, agentHandler);
            AgentManager.getInstance().register(value, ms);
            InjectManager.getInstance().update(entry.getKey(), o);
        }
    }
}
